<?php
/**
 * Http.php
 *
 * @package reepu.com
 * @version {$Id$}
 * @copyright 2009-2018 Shanghai Reepu Information Tech. Co., Ltd.
 * @license Commercial
 * @author Boolean since.
 * @datetime 2018-12-06 22:32
 * =================================================================
 * 版权所有 (C) 2009-2018 Reepu.com，并保留所有权利。
 * 网站地址:http://www.reepu.com/
 * -----------------------------------------------------------------
 * 您只能在不用于商业目的的前提下对程序代码进行修改和使用；
 * 不允许对程序代码以任何形式任何目的的再发布。
 * =================================================================
 */

namespace Reepu\Phalcon\Swoole;

use Reepu;
use Swoole;
use Phalcon;

class Http extends Phalcon\Cli\Task
{
    protected $pid = -1;
    protected $server = null;
    protected $application = null;

    public function onConstruct()
    {
        $usage = new Usage();
        $usage->check(['swoole', 'phalcon']);

        $this->initialize();
    }

    public function initialize()
    {
        $this->server = new Swoole\Http\Server($this->swoole->http->host, $this->swoole->http->port);
        $this->server->on('WorkerStart', array($this, 'onWorkerStart'));
        $this->server->on('WorkerStop', array( $this, 'onWorkerStop' ) );
        $this->server->on('Shutdown', array( $this, 'onShutdown' ) );
        $this->server->on('Start', array( $this, 'onStart' ) );
        $this->server->on('Request', array( $this, 'onRequest' ));
        $this->server->on('Task', array( $this, 'onTask' ) );
        $this->server->on('Finish', array( $this, 'onFinish' ));
    }

    /**
     * 启动服务
     * @param array $params -d 守护进程启动
     */
    public function startAction(array $params = [])
    {
        try {
            // 打印服务信息
            $this->printInfo();

            $dispatch_mode = (isset($params[0]) && '-d' == strtolower($params[0])) ? 1 : 0;
            $this->server->set(array_merge($this->swoole->setting->toArray(), ['dispatch_mode' => $dispatch_mode]));
            $this->server->start(); // 启动服务
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }

    /**
     * 重启
     */
    public function restartAction() {
        try {
            echo 'restart';
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }

    /**
     * 重新加载
     */
    public function reloadAction() {
        try {
            echo 'reload';
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }

    /**
     * 关闭服务
     */
    public function stopAction() {
        try {
            echo 'stop';
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }

    /**
     * 此事件在Worker进程/Task进程启动时发生
     * @param Swoole\Server $server
     * @param int $worker_id
     */
    public function onWorkerStart(Swoole\Server $server, int $worker_id)
    {
        echo 'worker: '. $worker_id .' start', PHP_EOL;

        /**
         * The FactoryDefault Dependency Injector automatically registers the services that
         * provide a full stack framework. These default services can be overidden with custom ones.
         */
        $di = new Phalcon\Di\FactoryDefault();

        /**
         * Include web environment specific services
         */
        require APP_PATH . '/config/services_web.php';

        /**
         * Include Autoloader
         */
        include APP_PATH . '/config/loader.php';

        /**
         * Handle the request
         */
        $this->application = new Phalcon\Mvc\Application($di);
        $this->application->useImplicitView(false);

        echo "Http Server Start Success" . PHP_EOL;
    }

    /**
     * 此事件在worker进程终止时发生
     * @param Swoole\Server $server
     * @param int $worker_id
     */
    public function onWorkerStop(Swoole\Server $server, int $worker_id)
    {
        echo 'worker: '. $worker_id .'stopped', PHP_EOL;
    }

    /**
     * 此事件在Server正常结束时发生
     * @param Swoole\Server $server
     */
    public function onShutdown(Swoole\Server $server)
    {
        echo 'worker: shutdown'. PHP_EOL;
    }

    /**
     * 启动后在主进程（master）的主线程回调
     * @param Swoole\Server $server
     */
    public function onStart(Swoole\Server $server)
    {
        echo 'Http Server Starting...' . PHP_EOL;

        if (php_uname('s') != 'Darwin') {
            cli_set_process_title("swoole server");
        }
    }

    public function onRequest(Swoole\Http\Request $request, Swoole\Http\Response $response)
    {
        try {
            ob_start();
            $this->application->sendHeadersOnHandleRequest($request->header);
            $this->application->sendCookiesOnHandleRequest($request->cookie);

            //$response->gzip(1);
            $path_info = $request->server['path_info'];

            if (empty($path_info)) {
                throw new \Exception('error request no path_info!', 500);
            } else {
                $handle = $this->application->handle($path_info);

                // 返回的Cookies
                if (!empty($handle->getCookies())) {

                }

                // 发送状态码
                $response->status($handle->getStatusCode());

                foreach ($handle->getHeaders()->toArray() as $key => $val) {
                    $response->header($key, $val);
                }

                $res = $handle->getContent();
            }

            ob_clean();
            $response->end($res);
        } catch (\Exception $e) {
            $response->status($e->getCode());
            $response->end($e->getMessage());
        }
    }

    /**
     * 有新的连接进入时，在worker进程中回调
     * @param Swoole\Server $server
     * @param int $fd
     * @param int $reactorId
     */
    public function onConnect(Swoole\Server $server, int $fd, int $reactorId) {

    }

    /**
     * 接收到数据时回调此函数，发生在worker进程中
     * @param Swoole\Server $server
     * @param int $fd TCP客户端连接的唯一标识符
     * @param int $reactor_id TCP连接所在的Reactor线程ID
     * @param string $data 收到的数据内容，可能是文本或者二进制内容
     */
    public function onReceive(Swoole\Server $server, int $fd, int $reactor_id, string $data) {

    }

    /**
     * 在task_worker进程内被调用
     * @param Swoole\Server $server
     * @param int $task_id 任务ID，由swoole扩展内自动生成，用于区分不同的任务
     * @param int $src_worker_id 来自于哪个worker进程
     * @param mixed $data 任务的内容
     */
    public function onTask(Swoole\Server $server, int $task_id, int $src_worker_id, mixed $data)
    {

    }

    /**
     * 当worker进程投递的任务在task_worker中完成时，task进程会通过swoole_server->finish()方法将任务处理的结果发送给worker进程。
     * @param Swoole\Server $server
     * @param int $task_id 任务的ID
     * @param string $data 任务处理的结果内容
     */
    public function onFinish(Swoole\Server $server, int $task_id, string $data)
    {
        echo 'finished', PHP_EOL;
    }

    /**
     * TCP客户端连接关闭后，在worker进程中回调此函数
     * @param Swoole\Server $server
     * @param int $fd TCP客户端连接的唯一标识符
     * @param int $reactor_id TCP连接所在的Reactor线程ID
     */
    public function onClose(Swoole\Server $server, int $fd, int $reactor_id) {

    }

    /**
     * 打印服务信息
     */
    protected function printInfo()
    {
        $this->pid = getmypid();
        echo "Process  ID：{$this->pid}" . PHP_EOL;
        echo "Listen Host：{$this->swoole->http->host}" . PHP_EOL;
        echo "Listen Port：{$this->swoole->http->port}" . PHP_EOL;
    }
}